package com.epam.mycollections.sets;

import com.epam.mycollections.interfaces.MyMap;
import com.epam.mycollections.interfaces.MySet;
import com.epam.mycollections.maps.MyHashMap;

import java.util.Iterator;

/**
 * My implementation of Hash Set data structure
 *
 * @author Iurii Miedviediev
 * @version 1.0 Build 04.08.2014
 */
public class MyHashSet<E> implements MySet<E>{

    protected MyHashMap<E, Object> map;

    public MyHashSet(int initCapacity, float loadFactor) {
        map = new MyHashMap<E, Object>(initCapacity, loadFactor);
    }

    public MyHashSet(int initCapacity) {
        map = new MyHashMap<E, Object>(initCapacity);
    }

    public MyHashSet() {
        map = new MyHashMap<E, Object>();
    }

    /**
     * Delete an element from the set
     * @param element element to delete
     * @return deleted element
     */
    @Override
    public E delete(E element) {
        MyMap.Entry<E, Object> entry = map.remove(element);
        if(entry == null) {
            return null;
        }
        return entry.getKey();
    }

    /**
     * Clear all elements from the set
     */
    @Override
    public void clear() {
        map.clear();
    }

    /**
     * Check if current set is empty
     * @return true if current set has no elements, false otherwise
     */
    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    /**
     * Add new element to the set if there is no identical to it
     * @param element new element
     */
    @Override
    public void add(E element) {
        map.put(element, "");
    }

    /**
     * Add an array of elements to the set
     * @param elements set of elements to add
     */
    @Override
    public void addAll(E[] elements) {
        for(E element : elements) {
            this.add(element);
        }
    }

    /**
     * Check if current set contains given element
     * @param element element to check
     * @return true if element is in the set, false otherwise
     */
    @Override
    public boolean contains(E element) {
        return map.containsKey(element);
    }

    /**
     * Compute the size of the set
     * @return number of elements in the curent set
     */
    @Override
    public int size() {
        return map.size();
    }

    /**
     * Iterator over the elements of the set
     * @return Iterator over the elements of the set
     */
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Iterator<MyMap.Entry<E,Object>> iter = map.entryIterator();
            @Override
            public boolean hasNext() {
                return iter.hasNext();
            }
            @Override
            public E next() {
                MyMap.Entry<E, Object> next = iter.next();
                if(next == null) {
                    return null;
                } else {
                    return next.getKey();
                }
            }
            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    /**
     * Convert hashset into array of elements
     * @return array of elements from the hashset
     */
    @Override
    public Object[] toArray() {
        Iterator<E> iter = this.iterator();
        Object[] result = new Object[this.size()];
        int position = 0;
        while(iter.hasNext()) {
            result[position] = iter.next();
        }
        return result;
    }
}